package cate.game.opponent;

import cate.common.util.XT;

import java.util.*;

public class Opponents<T extends Opponent> {

    /** 非玩家 */
    protected Map<String,T> npcs = new HashMap<>();

    /** 玩家 */
    protected Map<String, T> players = new HashMap<>();

    public void addNpc(T item) {
        this.npcs.put(item.uid(), item);
    }

    public void updateNpcList(Map<String, ? extends T> items) {
        this.npcs.clear();
        this.npcs.putAll(items);
    }

    public T find(String uid){
        T t = findNpc(uid);
        if(t == null){
            t = findPlayer(uid);
        }
        return  t;
    }

    public T findNpc(String uid) {
        return npcs.get(uid);
    }

    public void addPlayer(T item) {
        this.players.put(item.uid(), item);
    }

    public void updatePlayerList(Map<String, ? extends T> items) {
        this.players.clear();
        this.players.putAll(items);
    }

    public T findPlayer(String uid) {
        return players.get(uid);
    }

    /** 查找更高的对手 */
    public List<T> findHigherOppoList(OpponentFindParam ofp) {
        List<T> src = new ArrayList<>();
        if (ofp.part == OpponentFindParam.PART_NPC
                || ofp.part == OpponentFindParam.PART_NPC_AND_PLAYER) {
            for (T item : this.npcs.values()) {
                if (!ofp.excludeUids.contains(item.uid())) {
                    src.add(item);
                }
            }
        }
        if (ofp.part == OpponentFindParam.PART_PLAYER
                || ofp.part == OpponentFindParam.PART_NPC_AND_PLAYER) {
            for (T item : this.players.values()) {
                if (!ofp.excludeUids.contains(item.uid())) {
                    src.add(item);
                }
            }
        }

        List<T> targetList = new ArrayList<>();
        if (src.isEmpty()) {
            return targetList;
        }

        if (OpponentFindParam.RULE_POINTS == ofp.rule) {
            src.sort(Comparator.comparing(T::getPoints));
            for (int i = 0; i < src.size() && targetList.size() < ofp.wantNum; ++i) {
                T item = src.get(i);
                if (item.getPoints() > ofp.points) {
                    targetList.add(item);
                }
            }
        } else if (OpponentFindParam.RULE_POWER == ofp.rule) {
            src.sort(Comparator.comparing(T::getPower));
            for (int i = 0; i < src.size() && targetList.size() < ofp.wantNum; ++i) {
                T item = src.get(i);
                if (item.getPower() > ofp.power) {
                    targetList.add(item);
                }
            }
        }

        return targetList;
    }

    /** 查找竞争对手 */
    public List<T> find(OpponentFindParam ofp) {
        List<T> src = new ArrayList<>();
        if (ofp.part == OpponentFindParam.PART_NPC
                || ofp.part == OpponentFindParam.PART_NPC_AND_PLAYER) {
            for (T item : this.npcs.values()) {
                if (!ofp.excludeUids.contains(item.uid())) {
                    src.add(item);
                }
            }
        }
        if (ofp.part == OpponentFindParam.PART_PLAYER
                || ofp.part == OpponentFindParam.PART_NPC_AND_PLAYER) {
            for (T item : this.players.values()) {
                if (!ofp.excludeUids.contains(item.uid())) {
                    src.add(item);
                }
            }
        }
        List<T> op = null;
        switch (ofp.rule) {
            case OpponentFindParam.RULE_POINTS:
                op = findByPoints(src, ofp);
                break;
            case OpponentFindParam.RULE_POWER:
                op = findByPower(src, ofp);
                break;
            case OpponentFindParam.RULE_POWER_RANGE:
                op = findByPowerRange(src, ofp);
                break;
            default:
                break;
        }
        return op;
    }

    /** 根据积分游标查找对手 */
    private List<T> findByPoints(List<T> src, OpponentFindParam ofp) {
        src.sort(Comparator.comparing(T::getPoints));
        long[] valArr = new long[src.size()];
        for (int i = 0; i < src.size(); i++) {
            valArr[i] = src.get(i).getPoints();
        }
        SectionIndex si = new SectionIndex(valArr, ofp.points, ofp.wantNum);
        return section(src, si);
    }

    /** 根据战力游标查找对手 */
    public List<T> findByPower(List<T> src, OpponentFindParam ofp) {
        src.sort(Comparator.comparing(T::getPower));
        long[] valArr = new long[src.size()];
        for (int i = 0; i < src.size(); i++) {
            valArr[i] = src.get(i).getPower();
        }
        SectionIndex si = new SectionIndex(valArr, ofp.power, ofp.wantNum);
        return section(src, si);
    }

    private List<T> section(List<T> src, SectionIndex si) {
        List<T> candidate = new ArrayList<>();
        for (int i = 0; i < src.size(); i++) {
            if (i >= si.indexBeg && i <= si.indexEnd) {
                candidate.add(src.get(i));
            }
        }
        return candidate;
    }

    /** 根据战力范围查找对手 */
    private List<T> findByPowerRange(List<T> src, OpponentFindParam ofp) {
        List<T> candidate = new ArrayList<>();
        for (T item : src) {
            if (item.getPower() >= ofp.powerBeg && item.getPower() <= ofp.powerEnd) {
                candidate.add(item);
            }
        }
        return XT.randomPick(candidate, ofp.wantNum, false);
    }

    public int getNpcNum() {
        return this.npcs.size();
    }

    public int getPlayerNum() {
        return this.players.size();
    }

    public String ct() {
        return "npcList.size=" + this.npcs.size() +
                ", playerList.size=" + this.players.size();
    }
}
